package com.sltx.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
import java.util.concurrent.TimeUnit;



/*
* Redis拦截器
*
* */
@Slf4j
public class AccessLimintInterceptor implements HandlerInterceptor {
	@Resource
	private RedisTemplate<String, Object> redisTemplate;

	/**
	 * 多长时间内
	 */
	@Value("${interfaceAccess.second}")
	private Long second = 10L;

	/**
	 * 访问次数
	 */
	@Value("${interfaceAccess.requestCount}")
	private Long requestCount = 3L;

	/**
	 * 禁用时长--单位/秒
	 */
	@Value("${interfaceAccess.lockTime}")
	private Long lockTime = 10L;

	/**
	 * 锁住时的key前缀
	 */
	public static final String LOCK_PREFIX = "LOCK";

	/**
	 * 统计次数时的key前缀
	 */
	public static final String COUNT_PREFIX = "COUNT";


		public static String getClientIp(HttpServletRequest request) {
			String ipAddress = request.getHeader("X-Forwarded-For");
			if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
				ipAddress = request.getHeader("X-Real-IP");
			}
			if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
				ipAddress = request.getRemoteAddr();
			}
			// 如果使用 X-Forwarded-For 头，可能包含多个 IP 地址，第一个为客户端真实 IP
			if (ipAddress != null && ipAddress.contains(",")) {
				ipAddress = ipAddress.split(",")[0].trim();
			}
			return ipAddress;
		}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

		String uri = request.getRequestURI();
		String clientIp = getClientIp(request);//得到的就是访问者真实ip地址
		//String ip = request.getRemoteAddr(request); //这里忽略代理软件方式访问，默认直接访问，也就是获取得到的就是访问者真实ip地址
		String lockKey = LOCK_PREFIX + clientIp + uri;
		Object isLock = redisTemplate.opsForValue().get(lockKey);
		if(Objects.isNull(isLock)){
			// 还未被禁用
			String countKey = COUNT_PREFIX + clientIp + uri;
			Object count = redisTemplate.opsForValue().get(countKey);
			if(Objects.isNull(count)){
				// 首次访问
				log.info("首次访问");
				redisTemplate.opsForValue().set(countKey,1,second, TimeUnit.SECONDS);
			}else{
				// 此用户前一点时间就访问过该接口
				if((Integer)count < requestCount){
					// 放行，访问次数 + 1
					redisTemplate.opsForValue().increment(countKey);
				}else{
					log.info("{}禁用访问{}",clientIp, uri);
					// 禁用
					redisTemplate.opsForValue().set(lockKey, 1,lockTime, TimeUnit.SECONDS);
					// 删除统计
					redisTemplate.delete(countKey);
					throw new RuntimeException("请勿点击那么快，稍等一下！");
				}
			}
		}else{
			// 此用户访问此接口已被禁用
			throw new RuntimeException("请勿点击那么快，稍等一下！");
		}
		return true;
	}
}
